#include "stdafx.h"
#include "GbrHttpServ.h"

CGbrHttpServ::CGbrHttpServ(const wchar_t *fullyQualifiedUrl)
{
	hReqQueue = NULL;
	qualifiedUrl = fullyQualifiedUrl;
	HTTPAPI_VERSION HttpApiVersion = HTTPAPI_VERSION_1 ;
	currentError = HttpInitialize(HttpApiVersion, HTTP_INITIALIZE_SERVER, NULL) ;
	//HANDLE *phReqQueue = &hReqQueue;
	if (ERROR_SUCCESS == (currentError = HttpInitialize(HttpApiVersion, HTTP_INITIALIZE_SERVER, NULL))
		&& ERROR_SUCCESS == (currentError = HttpCreateHttpHandle(&hReqQueue,0))
		&& ERROR_SUCCESS == (currentError = HttpAddUrl(hReqQueue, fullyQualifiedUrl, NULL)))
	{
		RequestBufferLength = sizeof(HTTP_REQUEST) + 2048; // Allocate a 2 KB buffer. This size should work for most requests. The buffer size can be increased if required. Space is also required for an HTTP_REQUEST structure.
	    pRequest = (PHTTP_REQUEST)AllocMem(RequestBufferLength);
		if (!pRequest)
		{
			currentError = ERROR_NOT_ENOUGH_MEMORY;
			LogText("Out of memory") ;
		}
		else
			LogText("%ws\n", fullyQualifiedUrl) ;
	}
}

CGbrHttpServ::~CGbrHttpServ(void)
{
    if(pRequest)
        FreeMem(pRequest);
	HttpRemoveUrl(hReqQueue, qualifiedUrl);
	CloseHandle(hReqQueue);
	HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);
}

ULONG CGbrHttpServ::CurrentError()
{
	return currentError;
}

ULONG CGbrHttpServ::SendAndLog(const USHORT statusCode, PCSTR pStrSendReason, PCSTR pStrSendContent, PSTR pStrLog, PCWSTR pWstrLog)
{
	LogText(pStrLog, pWstrLog);
	return SendDirect(statusCode, pStrSendReason, pStrSendContent);
}

DWORD CGbrHttpServ::DoReceiveRequests_SingleThreaded()
{
	ULONG result = ERROR_NOT_ENOUGH_MEMORY; // returned if initial pRequest malloc failed...
	while (this != NULL && NULL != pRequest) // :)
    {	//ZeroMem(pRequest, RequestBufferLength);
	    DWORD bytesRead;
        ULONG result = HttpReceiveHttpRequest(hReqQueue, requestId, 0, pRequest, RequestBufferLength, &bytesRead, NULL);
        if(NO_ERROR == result)
        {
            switch(pRequest->Verb)
            {
                case HttpVerbGET:
                    LogText("GET %ws \n", pRequest->CookedUrl.pFullUrl);
					{
						char sz[300] ;
						wchar_t *pW = (wchar_t *)pRequest->CookedUrl.pAbsPath;
						//if (CrackParameters(pW, &page, &pageSize, sz, 300))
						//{ // Output matching
						//	result = SendHttpResponse(hReqQueue, pRequest, page, pageSize, sz) ;
						//}
						//else
						{ // Output usage
							char szQueryString[1000] ;
							*szQueryString = 0;
							size_t i = 0 ;
							while (i < 999 && *pW != (wchar_t)0)
							{
								szQueryString[i++] = (char)*(pW++) ;
							}
							szQueryString[i] = 0 ;
							wsprintfA(sz, USAGE_STRING,
								szQueryString) ;
							result = SendDirect(200, "OK", sz);
						}
					}
                    break;
				case HttpVerbUnparsed: result=SendAndLog(503, "Not implemented", NULL, "Verb \"unparsed\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbUnknown: result=SendAndLog(503, "Not implemented", NULL, "Verb \"unknown\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbInvalid: result=SendAndLog(503, "Not implemented", NULL, "Verb \"invalid\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbOPTIONS: result=SendAndLog(503, "Not implemented", NULL, "Verb \"options\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbHEAD: result=SendAndLog(503, "Not implemented", NULL, "Verb \"head\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbPOST: result=SendAndLog(503, "Not implemented", NULL, "Verb \"post\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbPUT: result=SendAndLog(503, "Not implemented", NULL, "Verb \"put\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbDELETE: result=SendAndLog(503, "Not implemented", NULL, "Verb \"delete\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbTRACE: result=SendAndLog(503, "Not implemented", NULL, "Verb \"trace\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbCONNECT: result=SendAndLog(503, "Not implemented", NULL, "Verb \"connect\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbTRACK: result=SendAndLog(503, "Not implemented", NULL, "Verb \"track\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;  // used by Microsoft Cluster Server for a non-logged trace
				case HttpVerbMOVE: result=SendAndLog(503, "Not implemented", NULL, "Verb \"move\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbCOPY: result=SendAndLog(503, "Not implemented", NULL, "Verb \"copy\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbPROPFIND: result=SendAndLog(503, "Not implemented", NULL, "Verb \"propfind\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbPROPPATCH: result=SendAndLog(503, "Not implemented", NULL, "Verb \"proppatch\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbMKCOL: result=SendAndLog(503, "Not implemented", NULL, "Verb \"mkcol\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbLOCK: result=SendAndLog(503, "Not implemented", NULL, "Verb \"lock\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbUNLOCK: result=SendAndLog(503, "Not implemented", NULL, "Verb \"unlock\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
				case HttpVerbSEARCH: result=SendAndLog(503, "Not implemented", NULL, "Verb \"search\" not implemented, url=%ws", pRequest->CookedUrl.pFullUrl); break;
                default:
					result=SendAndLog(503, "Not implemented", NULL, "Unknown verb, url=%ws", pRequest->CookedUrl.pFullUrl); 
					break;
            }
            if(result == NO_ERROR)
				requestId = HTTP_NULL_ID; // Reset the Request ID to handle the next request.
        }
        else if(result == ERROR_MORE_DATA)
        {	// The input buffer was too small to hold the request headers. Increase the buffer size and call the API again. When calling the API again, handle the request that failed by passing a RequestID. This RequestID is read from the old buffer.
            requestId = pRequest->RequestId;
            RequestBufferLength = bytesRead;
            if (NULL == (pRequest = (PHTTP_REQUEST)ReallocMem(pRequest, RequestBufferLength)))
                result = ERROR_NOT_ENOUGH_MEMORY;
        }
        else if(ERROR_CONNECTION_INVALID == result && !HTTP_IS_NULL_ID(&requestId))
        {
            // The TCP connection was corrupted by the peer when attempting to handle a request with more buffer. Continue to the next request.
			requestId = HTTP_NULL_ID; // Reset the Request ID to handle the next request.
        }
    }

    return result; // only on ERROR_NOT_ENOUGH_MEMORY?
}
